           package com.java.diagnostics.visualizer.displayer.plot;
           
           import com.java.diagnostics.visualizer.data.DataPoint;
           import com.java.diagnostics.visualizer.data.TupleData;
           import com.java.diagnostics.visualizer.properties.OutputProperties;
           import java.util.HashMap;
           import java.util.Map;
           import org.eclipse.swt.graphics.Point;
           
           public class PointConverter
           {
             private final int[] quadrantDensities;
             private int plotHeight;
             private int plotWidth;
             private int plotLeft;
             private int plotBottom;
             private int plotRight;
             private int plotTop;
             private boolean calculateLegendPosition = true;
           
             private boolean storingMapping = true;
             private XPositionConverter xConverter;
             private YPositionConverter yConverter;
             private int lastX = -1;
           
             private int lastY = -1;
             private Map<Point, DataPoint> points;
             private int maxSearchRadius;
             private String xUnits;
             private String yUnits;
           
             public PointConverter(XPositionConverter xConverter, YPositionConverter yConverter)
             {
               this.quadrantDensities = new int[4];
               this.xConverter = xConverter;
               this.yConverter = yConverter;
               this.points = new HashMap();
               this.maxSearchRadius = new LinePlotPreferenceHelper().getCursorFuzziness();
             }
           
             public void setCalculateLegendPosition(boolean calculate) {
               this.calculateLegendPosition = calculate;
             }
           
             public void refreshLimits(int plotLeft, int plotRight, int plotBottom, int plotTop)
             {
               this.plotLeft = (plotLeft + 1);
               this.plotRight = (plotRight - 1);
               this.plotBottom = (plotBottom - 1);
               this.plotTop = (plotTop + 1);
               this.plotWidth = (this.plotRight - this.plotLeft);
               this.plotHeight = Math.abs(this.plotTop - this.plotBottom);
           
               this.xConverter.updateLimits(this.plotLeft, this.plotRight);
               this.yConverter.updateLimits(this.plotBottom, this.plotTop);
           
               this.points = new HashMap();
             }
           
             public Point convertToPoint(DataPoint point) {
               double xValue = point.getX(this.xUnits);
               int x = this.xConverter.convertToPosition(xValue);
               double yValue = point.getY(this.yUnits);
               int y = this.yConverter.convertToPosition(yValue);
           
               if (this.calculateLegendPosition)
               {
                 if (isExtremeLeft(x)) {
                   if (isExtremeTop(y))
                   {
                     this.quadrantDensities[0] += 1;
                   } else if (isExtremeBottom(y))
                   {
                     this.quadrantDensities[2] += 1;
                   }
                 }
                 else if (isExtremeRight(x)) {
                   if (isExtremeTop(y))
                   {
                     this.quadrantDensities[1] += 1;
                   } else if (isExtremeBottom(y))
                   {
                     this.quadrantDensities[3] += 1;
                   }
                 }
               }
               Point plotPoint = new Point(x, y);
           
               if ((x != this.lastX) || (y != this.lastY)) {
                 if (this.storingMapping) {
                   this.points.put(plotPoint, point);
                 }
                 this.lastX = x;
                 this.lastY = y;
               }
               return plotPoint;
             }
           
             private boolean isExtremeBottom(int y)
             {
               return y > this.plotBottom - this.plotHeight / 3;
             }
           
             private boolean isExtremeTop(int y) {
               return y < this.plotTop + this.plotHeight / 3;
             }
           
             private boolean isExtremeRight(int x) {
               return x > this.plotRight - this.plotWidth / 3;
             }
           
             private boolean isExtremeLeft(int x) {
               return x < this.plotLeft + this.plotWidth / 3;
             }
           
             public void updateLabelsAndAxes(OutputProperties properties, TupleData data) {
               this.xUnits = properties.getXUnits(data);
               this.yUnits = properties.getYUnits(data);
               this.xConverter.updateLabelsAndAxes(properties, data);
               this.yConverter.updateLabelsAndAxes(properties, data);
             }
           
             public int calculateLegendPosition()
             {
               int position = 3;
               int startPosition = position;
               for (int i = startPosition; i < startPosition + this.quadrantDensities.length; i++) {
                 int newQuadrant = i % this.quadrantDensities.length;
                 if (this.quadrantDensities[newQuadrant] < this.quadrantDensities[position]) {
                   position = newQuadrant;
                 }
           
               }
           
               position++;
               return position;
             }
           
             public boolean legendIsTop(int position) {
               return position <= 2;
             }
           
             public boolean legendIsLeft(int position) {
               return position % 2 != 0;
             }
           
             public YPositionConverter getYConverter() {
               return this.yConverter;
             }
           
             public void setYConverter(YPositionConverter converter) {
               this.yConverter = converter;
             }
           
             public XPositionConverter getXConverter() {
               return this.xConverter;
             }
           
             public DataPoint findDataPoint(Point point) {
               DataPoint dataPoint = null;
               dataPoint = (DataPoint)this.points.get(point);
           
               int radius = 1;
               while ((dataPoint == null) && (radius <= this.maxSearchRadius))
               {
                 int newX = point.x + radius;
           
                 for (int i = -radius; i <= radius; i++) {
                   if (dataPoint == null) {
                     int newY = point.y + i;
                     Point newPoint = new Point(newX, newY);
                     dataPoint = (DataPoint)this.points.get(newPoint);
                   }
                 }
                 if (dataPoint == null)
                 {
                   newX = point.x - radius;
                   for (int i = -radius; i <= radius; i++) {
                     if (dataPoint == null) {
                       int newY = point.y + i;
                       Point newPoint = new Point(newX, newY);
                       dataPoint = (DataPoint)this.points.get(newPoint);
                     }
                   }
           
                 }
           
                 if (dataPoint == null)
                 {
                   int newY = point.y - radius;
                   for (int i = -radius; i <= radius; i++) {
                     if (dataPoint == null) {
                       newX = point.x + i;
                       Point newPoint = new Point(newX, newY);
                       dataPoint = (DataPoint)this.points.get(newPoint);
                     }
                   }
                 }
                 if (dataPoint == null)
                 {
                   int newY = point.y + radius;
                   for (int i = -radius; i <= radius; i++) {
                     if (dataPoint == null) {
                       newX = point.x + i;
                       Point newPoint = new Point(newX, newY);
                       dataPoint = (DataPoint)this.points.get(newPoint);
                     }
                   }
                 }
           
                 radius++;
               }
           
               return dataPoint;
             }
           }

